/*
	       File: frmWorkFlowEditor.cs
	Create Date: 2007-09-03
	    Version:

	Description:


	 Change log:


*/
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Configuration;
using System.Data;
using System.Drawing;
using System.Drawing.Design;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Xml;

using System.Workflow.ComponentModel;
using System.Workflow.Activities;
using System.Workflow.ComponentModel.Compiler;

using GuerillaProgrammer.FileProcessor;
using GuerillaProgrammer.FileProcessor.Settings;

namespace GuerillaProgrammer.FileProcessor
{
    public partial class frmWorkFlowEditor : Form
    {
        #region Private member fields
        private string _WorkflowFileName = string.Empty;
        private TypeProvider _TypeProvider = null;
        private WorkflowDesignerConfiguration _Configuration;
        #endregion

        #region Constructors and cleanup methods
        public frmWorkFlowEditor()
        {
            _TypeProvider = new TypeProvider(new ServiceContainer());
            InitializeComponent();
            workflowDesigner.TypeProvider = _TypeProvider;

            _Configuration = ConfigurationManager.ReadWorkflowConfiguration(GetConfigurationPath());
        }
        #endregion

        #region Private implementation methods
        private void SetApplicationTitle(String fileName)
        {
            if (String.IsNullOrEmpty(fileName))
            {
                this.Text = "Custom Workflow Designer";
            }
            else
            {
                this.Text = String.Format("Custom Workflow Designer: {0}",Path.GetFileName(fileName));
            }
        }
        private Boolean SaveWorkflowDefinition(String fileName)
        {
            Boolean result = false;
            try
            {
                //let the designer handle the save operation
                if (workflowDesigner.SaveWorkflow(fileName))
                {
                    _WorkflowFileName = fileName;
                    result = true;
                }
                else
                {
                    MessageBox.Show("Unable to save markup file","Error saving markup",MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            catch (Exception exception)
            {
                MessageBox.Show(String.Format("Exception saving workflow: {0}",exception.Message),"Exception in SaveWorkflowDefinition",MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            return result;
        }
        private void AddClassToWorkflowDecl(string fileName)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(fileName);
            XmlAttribute attrib = doc.CreateAttribute("x", "Class", "http://schemas.microsoft.com/winfx/2006/xaml");
            string className = string.Format("wf{0}", Path.GetFileNameWithoutExtension(fileName));
            attrib.Value = className;
            doc.DocumentElement.Attributes.Append(attrib);
            doc.Save(fileName);
        }
        private string GetConfigurationPath()
        {
            string configurationPath = System.Configuration.ConfigurationManager.AppSettings["configPath"];
            if (true == string.IsNullOrEmpty(configurationPath))
            {
                configurationPath = ".\\configuration.xml";
            }

            if (false == File.Exists(configurationPath))
            {
                MessageBox.Show("Configuration missing!", "Cannot find the configuration file.\nThe designer cannot start until this is fixed.");
                throw new FileNotFoundException("The configuration file cannot be found.");
            }

            return configurationPath;
        }
        #endregion

        #region Class properties
        private WorkflowDesignerConfiguration Configuration
        {
            get
            {
                if (null == _Configuration)
                {
                    _Configuration = ConfigurationManager.ReadWorkflowConfiguration(GetConfigurationPath());
                }

                return _Configuration;
            }
        }
        #endregion

        #region Events handlers
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }
        private void newWorkflowToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                frmNewWorkflow newWorkflowName = new frmNewWorkflow();
                if (DialogResult.Cancel == newWorkflowName.ShowDialog())
                {
                    return;
                }
                //let the designer create a new workflow
                //base on the selected workflow Type
                _WorkflowFileName = newWorkflowName.WorkflowName;
                if (true == this.workflowDesigner.CreateNewWorkflow(typeof(SequentialWorkflowActivity), Path.GetFileNameWithoutExtension(_WorkflowFileName)))
                {
                    saveWorkflowAsToolStripMenuItem_Click(sender, e);
                    SetApplicationTitle(_WorkflowFileName);
                }
                else
                {
                    MessageBox.Show("Unable to create new workflow", "Error creating workflow",MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            catch (Exception exception)
            {
                MessageBox.Show(String.Format("Exception creating workflow: {0}",exception.Message),"Exception in CreateNewWorkflow",MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        private void openWorkflowToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SetApplicationTitle(null);
            OpenFileDialog openFile = new OpenFileDialog();
            openFile.InitialDirectory = ConfigurationManager.GetXOMLDirectory(Configuration);
            openFile.Filter = "xoml files (*.xoml)|*.xoml|All files (*.*)|*.*";
            openFile.FilterIndex = 1;
            
            if (openFile.ShowDialog() == DialogResult.OK)
            {
                String fileName = openFile.FileName;
                try
                {
                    //tell the designer to load the workflow markup
                    if (workflowDesigner.LoadWorkflow(fileName))
                    {
                        _WorkflowFileName = fileName;
                        SetApplicationTitle(fileName);
                    }
                    else
                    {
                        MessageBox.Show("Unable to load markup file","Error loading markup",MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
                catch (Exception exception)
                {
                    MessageBox.Show(String.Format("Exception loading workflow: {0}",exception.Message), "Exception in LoadWorkflow",MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }
        private void saveWorkflowToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!String.IsNullOrEmpty(_WorkflowFileName))
            {
                SaveWorkflowDefinition(_WorkflowFileName);
            }
        }
        private void saveWorkflowAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveFile = new SaveFileDialog();
            saveFile.InitialDirectory = ConfigurationManager.GetXOMLDirectory(Configuration);
            saveFile.Filter = "xoml files (*.xoml)|*.xoml|All files (*.*)|*.*";
            saveFile.FilterIndex = 1;
            saveFile.FileName = _WorkflowFileName;
            if (saveFile.ShowDialog() == DialogResult.OK)
            {
                if (SaveWorkflowDefinition(saveFile.FileName))
                {
                    SetApplicationTitle(saveFile.FileName);
                }
                else
                {
                    SetApplicationTitle(null);
                }
            }
        }
        private void buildWorkflowToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (false == File.Exists(_WorkflowFileName))
            {
                if (false == SaveWorkflowDefinition(_WorkflowFileName))
                {
                    MessageBox.Show("Unable to compile!", "The workflow could not be saved!");
                    return;
                }
            }

            AddClassToWorkflowDecl(_WorkflowFileName); //put the class attribute on to the workflow

            SaveFileDialog sfd = new SaveFileDialog();
            sfd.InitialDirectory = ConfigurationManager.GetAssemblyDirectory(Configuration);
            sfd.Filter = "assembly files (*.dll)|*.dll|All files (*.*)|*.*";
            sfd.FilterIndex = 1;
            sfd.FileName = Path.GetFileNameWithoutExtension(_WorkflowFileName) + ".dll";
            if (DialogResult.OK != sfd.ShowDialog())
            {
                return;
            }

            string[] files = { _WorkflowFileName };

            WorkflowCompiler compiler = new WorkflowCompiler();
            WorkflowCompilerParameters parameters = new WorkflowCompilerParameters();
            parameters.GenerateInMemory = false;
            parameters.OutputAssembly = sfd.FileName;
            parameters.MainClass = Path.GetFileNameWithoutExtension(_WorkflowFileName);
            //have to add the reference to GuerillaProgrammer activities!
            ConfigurationManager.AddLibraryDirectories(parameters.LibraryPaths, Configuration);
            ConfigurationManager.AddReferencedAssemblies(parameters.ReferencedAssemblies, Configuration);            
            
            WorkflowCompilerResults results = compiler.Compile(parameters, files);
            if (0 != results.Errors.Count)
            {

                StringBuilder message = new StringBuilder();
                message.Append(string.Format("There are {0} errors in the workflow.\n", results.Errors.Count));
                foreach (CompilerError error in results.Errors)
                {
                    message.Append(string.Format("Error ({0}) - {1}\n", error.ErrorNumber, error.ErrorText));
                }
                MessageBox.Show(message.ToString());
            }
            else
            {
                MessageBox.Show(string.Format("{0} was built.",Path.GetFileName(_WorkflowFileName)), "Build workflow");
            }
        }
        #endregion
    }
}